#include "Space.h"

Space::Space()
{
	m_game = NULL;
}
Space::Space(Game *p_game)
{
	m_game = p_game;
}
Space::~Space()
{
}


std::vector<Object*> Space::getObjects()
{
	return m_objects;
}
std::list<Widget*> Space::getWidgets()
{
	return m_widgets;
}


void Space::addObject(Object *p_Object)
{
	Lock();
	m_objects.push_back((Object*)p_Object);
	Unlock();
}
void Space::removeObject(Object* p_object)
{
	bool lol=false;
	for (	std::vector<Object*>::iterator itr = m_objects.begin();
			itr!=m_objects.end() && !lol; itr++)
	{
		if ( p_object == (*itr) )
		{
			m_objects.erase(itr);
			lol=true;
		}
	}
}


void Space::clear()
{
	Lock();
	m_objects.clear();
	m_widgets.clear();
	Unlock();
}
void Space::collisionDetect()
{
	for(unsigned int i = 0;i < m_objects.size(); i++)
	{
		for(unsigned int j = 0; j < m_objects.size(); j++)
		{
			Object *p1 = (Object*)m_objects.at(i);
			Object *p2 = (Object*)m_objects.at(j);
			if (p1 != p2)
			{
				if(p1->collide(p2))
				{
					if (p1->getType() == MISSILE)
						p1->kill();
					if (p2->getType() == MISSILE)
						p2->kill();
				}
			}
		}
	}
}

void Space::blowObject(Object* p_object)
{
	double explosion_radius;
	bool explosion_crit = (bool)(randInt(1,100) <= GC_CRIT_CHANCE);
	unsigned int explosion_power;
	Vector2 explosion_position = p_object->getPosition();

	switch ( p_object->getType() )
	{
		case MISSILE:
		{
			explosion_radius = GC_MISSILE_BLOW_RADIUS;
			Missile* mis = (Missile*)p_object;
			explosion_power = mis->getPower();
			break;
		}
		case PLANET:
			explosion_radius = randInt(GC_PLANET_BLOW_RADIUS,GC_PLANET_BLOW_RADIUS+GC_PLANET_BLOW_RANGE);
			explosion_power = GC_PLANET_BLOW_DAMAGE;
			break;
		case STAR:
			explosion_radius = 10000;
			explosion_power = 10000;
			break;
		default:
			return;
	}

	if (explosion_crit)
	{
		m_widgets.push_back(new ExplosionEffect(explosion_position, color(255,100,20,255), explosion_radius));
		explosion_power = explosion_power * 2;
	} else {
		m_widgets.push_back(new ExplosionEffect(explosion_position, color(255,255,0,255), explosion_radius));
	}

	for(unsigned int i = 0;i < m_objects.size(); i++)
	{
		Object* other_object = m_objects.at(i);

		if (other_object != p_object && other_object->collide(explosion_radius, explosion_position))
		{
			other_object->damage(explosion_power);
			m_widgets.push_back(new DamageWidget(explosion_power, other_object->getPosition(), explosion_crit));
		}
	}
}

void Space::destroyDeadObjects()
{
	bool check_hp_again=true;
	while(check_hp_again)
	{
		check_hp_again=false;
		std::stack<Object*> to_remove;

		for(unsigned int i = 0;i < m_objects.size(); i++)
		{
			Object *p = m_objects.at(i);

			if (p->getHealth() <= 0)
				to_remove.push(p);
		}

		while(!to_remove.empty())
		{
			Object* obj = to_remove.top();
		
			if (!obj->doneExploding())
			{
				if (obj->useExplosionCharge()) // planets will return false if their global cooldown is in effect
				{
					blowObject(obj);
					check_hp_again=true;
				}
			}
			else
			{
				removeObject(obj);
			}
			to_remove.pop();
		}
	}
}

void Space::doPhysics(double p_dt)
{
	Lock();
	for(unsigned int i = 0;i < m_objects.size(); i++)
	{
		for(unsigned int j = i+1; j < m_objects.size(); j++)
		{
			m_objects.at(i)->calculateForce(m_objects.at(j));
		}
	}
	for(unsigned int k = 0; k < m_objects.size(); k++)
	{
		m_objects.at(k)->updatePosition(p_dt);
	}
	Unlock();

	Lock();
	collisionDetect();
	Unlock();

	
	Lock();
	for(unsigned int i = 0; i < m_objects.size(); i++)
	{
		m_objects.at(i)->tick();
	}
	Unlock();


	Lock();
	destroyDeadObjects();
	Unlock();


	Lock();
	std::list<Widget*>::iterator itr;
	for(itr = m_widgets.begin(); itr != m_widgets.end();)
	{
		Widget *w = *itr;
		w->tick();

		std::list<Widget*>::iterator old_itr = itr;
		itr++;

		if(w->getFinished())
		{
			m_widgets.erase(old_itr);
		}
	}
	Unlock();
}
